#include "media_stream.h"

#include <algorithm>
#include <inttypes.h>
#include <string.h>
#include <sys/prctl.h>
#include <sys/time.h>
#include <vector>
#include <cassert>
#include <memory>
#include <utility>
#include "camera_video_enc.h"
#include "audio_enc.h"
#include "base_log.h"
#include "media_stream_manager.h"

namespace El {
namespace Media {
StreamSourcePtr StreamSource::Create(int32_t ch, int32_t type)
{
    return std::make_shared<StreamSource>(ch, type);
}

StreamSource::StreamSource(int32_t ch, int32_t type) : ch_(ch), type_(type) {}

StreamSource::~StreamSource()
{
    Stop();
}

bool StreamSource::SetInfo(int32_t max, std::string name)
{
    max_ = max;
    name_ = name;
    return true;
}

int32_t StreamSource::Start()
{
    if (!start_) {
        LOG_INFO("StreamSource starting ch:{}, type:{}", ch_, type_);
        start_ = true;
        waitForIFrame_ = true;

        // 队列支持2秒缓存，2* 30fps = 60帧
        queue_ = std::make_unique<Base::BlockingQueue<Media::MediaFramePtr>>(name_, max_);

        if (!callbackManager_.IsEmpty()) {
            streamThread_ = std::make_unique<std::thread>(&StreamSource::StreamThread, this);
            LOG_INFO("StreamSource thread is starting ch:{}, type:{}", ch_, type_);
        }

        streamHandle_ = StreamSourceManager::GetInstance(ch_, type_).Start([this](const MediaFramePtr &frame) {
            if (waitForIFrame_) {
                if (frame->GetFrameType() != MEDIA_FRAME_I) {
                    LOG_DEBUG("Waiting for I-frame, dropping frame type:{}", frame->GetFrameType());
                    return;
                }
                waitForIFrame_ = false;
                LOG_INFO("Got first I-frame, starting normal operation");
            }

            bool ret = queue_->Push(frame, 0);
            if (!ret) {
                LOG_ERROR("queue is full size:{}, drop frame {}, waiting for next I-frame", queue_->Size(),
                          frame->ToString().c_str());
                waitForIFrame_ = true;
            }
        });

        // 立即请求I帧，确保快速显示首帧
        ForceIframe();
    }
    return true;
}

void StreamSource::Stop()
{
    if (!start_) {
        return;
    }
    start_ = false;
    waitForIFrame_ = true;

    StreamSourceManager::GetInstance(ch_, type_).Stop(streamHandle_);
    streamHandle_ = 0;

    queue_->SetActive(false);
    if (streamThread_) {
        streamThread_->join();
        streamThread_.reset();
    }

    callbackManager_.Clear();
    LOG_INFO("StreamSource stoped ch:{}, type:{}", ch_, type_);
}

int32_t StreamSource::Register(const Proc &proc)
{
    return callbackManager_.Register(proc);
}

void StreamSource::Unregister(int32_t handle)
{
    callbackManager_.Unregister(handle);
}

MediaFramePtr StreamSource::GetFrame(int32_t timeout)
{
    return queue_->Pop(timeout);
}

void StreamSource::StreamThread()
{
    while (start_) {
        auto media = queue_->Pop(20);
        if (!media) {
            continue;
        }
        callbackManager_.InvokeAll(media);
    }
    LOG_INFO("StreamSource thread is stopping ch:{}, type:{}", ch_, type_);
}

bool StreamSource::ForceIframe()
{
    return Hal::ICameraVideoEnc::GetInstance(ch_, type_).ForceIFrame();
}

bool StreamSource::GetEncFormat(VideoEncFormat &enc)
{
    return Hal::ICameraVideoEnc::GetInstance(ch_, type_).GetEncFormat(enc);
}

bool StreamSource::GetAudioEncFormat(AudioEncFormat &enc)
{
    return Hal::IAudioEnc::GetInstance(ch_, type_).GetEncFormat(enc);
}

} // namespace Media
} // namespace El